﻿#region Imports

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Windows.Forms;
using Andromeda.Forge.Business;
using Andromeda.Forge.Common;
using Andromeda.Forge.DataSource.DB;
using Andromeda.Forge.DataSource.DLL;
using Andromeda.Forge.Validations;
using ForgeIt.Forms;
using ForgeIt.Forms.Project.Datasource.DB;
using ForgeIt.Internal;
using ForgeIt.Properties;

#endregion

namespace ForgeIt.UserControls
{
    /// <summary>
    /// </summary>
    public partial class FoSolutionExplorerUserControl : UserControl
    {
        #region Delegates

        /// <summary>
        /// </summary>
        /// <param name="sender"> </param>
        /// <param name="args"> </param>
        /// <returns> </returns>
        public delegate void FoSolutionExplorerUserControlEventHandler(object sender, FoSolutionExplorerEventArgs args);

        #endregion

        #region TypesFilter enum

        /// <summary>
        ///   Enum with all the potential Filters for the FoSolutionExplorerUserControl
        /// </summary>
        [Flags]
        public enum TypesFilter
        {
            /// <summary>
            ///   Lists DLL Projects
            /// </summary>
            DLLProject = 0x01,

            /// <summary>
            ///   Lists DB Projects
            /// </summary>
            DBProject = 0x02,

            /// <summary>
            ///   List Business Projects
            /// </summary>
            BusinessProject = 0x04,

            /// <summary>
            ///   Lists DB Classes
            /// </summary>
            DBClass = 0x08,

            /// <summary>
            ///   Lists Business Classes
            /// </summary>
            BusinessClass = 0x16,

            /// <summary>
            ///   Lists All Classes
            /// </summary>
            AllClasses = 0x32,

            /// <summary>
            ///   Lists DB Properties
            /// </summary>
            DBProperty = 0x64,

            /// <summary>
            ///   Lists Business Properties
            /// </summary>
            BusinessProperty = 0x128,

            /// <summary>
            ///   Lists All Properties
            /// </summary>
            AllProperties = 0x256,

            /// <summary>
            ///   Lists business validations
            /// </summary>
            BusinessValidation = 0x512,

            /// <summary>
            ///   Lists all supported types
            /// </summary>
            All = 0x1024,

            /// <summary>
            ///   Lists Web projects
            /// </summary>
            WebProjects = 0x2048,

            /// <summary>
            ///   Lists Win projects
            /// </summary>
            WinProjects = 0x4096,

            /// <summary>
            ///   Lists Win Forms
            /// </summary>
            WinForm = 0x8192,

            /// <summary>
            ///   Lists Web Forms
            /// </summary>
            WebForm = 0x16384,

            /// <summary>
            ///   Lists Form Actions
            /// </summary>
            FormAction = 0x32768,

            /// <summary>
            ///   Lists Form Fields
            /// </summary>
            FormField = 0x65536
        }

        #endregion

        private FOSolution _solution;
        private TypesFilter _typesToShow;


        /// <summary>
        /// </summary>
        public FoSolutionExplorerUserControl()
        {
            InitializeComponent();
        }

        /// <summary>
        /// </summary>
        public Connect Connector { get; protected set; }

        /// <summary>
        /// </summary>
        /// <param name="connector"> </param>
        /// <param name="typesToShow"> </param>
        public void DataBind(Connect connector, TypesFilter typesToShow)
        {
            Connector = connector;
            if ((connector != null && connector.ForgeSolution == null) || _solution == null) return;

            if ((connector != null && connector.ForgeSolution != null))
                DataBind(connector.ForgeSolution, typesToShow);

            if (_solution != null)
                DataBind(_solution, typesToShow);
        }

        /// <summary>
        /// </summary>
        /// <param name="solution"> </param>
        /// <param name="typesToShow"> </param>
        public void DataBind(FOSolution solution, TypesFilter typesToShow)
        {
            _solution = solution;
            _typesToShow = typesToShow;
            treeView1.Nodes.Clear();

            var nodes = new List<FONode> {solution};

            nodes.AddRange(solution.AllProjects.Cast<FONode>());

            foreach (var node in nodes)
            {
                FillTree(null, node);
            }
        }

        private void FillTree(TreeNode node, FONode foNode)
        {
            CreateNode(ref node, foNode);

            // Do not cycle children of uncreated nodes
            if (node == null) return;

            foreach (FONode child in foNode.ChildNodes)
            {
                FillTree(node, child);
            }
        }

        private void CreateNode(ref TreeNode node, FONode foNode)
        {
            TreeNode[] find;
            var nodes = node != null ? node.Nodes : treeView1.Nodes;

            if ((_typesToShow & TypesFilter.All) != TypesFilter.All)
            {
                if ((_typesToShow & TypesFilter.DLLProject) != TypesFilter.DLLProject &&
                    foNode is FODataSourceDLLProject)
                {
                    return;
                }
                if ((_typesToShow & TypesFilter.DBProject) != TypesFilter.DBProject && foNode is FODataSourceDBProject)
                {
                    return;
                }
                if ((_typesToShow & TypesFilter.BusinessProject) != TypesFilter.BusinessProject &&
                    foNode is FOBusinessProject)
                {
                    return;
                }
                if ((_typesToShow & TypesFilter.DBClass) != TypesFilter.DBClass &&
                    (_typesToShow & TypesFilter.AllClasses) != TypesFilter.AllClasses && foNode is FODataSourceDBClass)
                {
                    return;
                }
                if ((_typesToShow & TypesFilter.BusinessClass) != TypesFilter.BusinessClass &&
                    (_typesToShow & TypesFilter.AllClasses) != TypesFilter.AllClasses && foNode is FOBusinessClass)
                {
                    return;
                }
                if ((_typesToShow & TypesFilter.DBProperty) != TypesFilter.DBProperty &&
                    (_typesToShow & TypesFilter.AllProperties) != TypesFilter.AllProperties &&
                    foNode is FODataSourceDBProperty)
                {
                    return;
                }
                if ((_typesToShow & TypesFilter.BusinessProperty) != TypesFilter.BusinessProperty &&
                    (_typesToShow & TypesFilter.AllProperties) != TypesFilter.AllProperties &&
                    foNode is FOBusinessProperty)
                {
                    return;
                }
                if ((_typesToShow & TypesFilter.BusinessValidation) != TypesFilter.BusinessValidation &&
                    foNode is FOPropertyValidationNode)
                {
                    return;
                }

                // TODO: Add support for UI projects
            }

            if (node != null)
            {
                find = node.Nodes.Find(foNode.GroupId, false);
                if (!string.IsNullOrEmpty(foNode.GroupKey))
                    nodes = find.Any()
                                ? find.First().Nodes
                                : node.Nodes.Add(foNode.GroupId, foNode.GroupKey, foNode.IdGroupImage,
                                                 foNode.IdGroupImage).Nodes;
            }

            if (GetImageId(foNode) == -1) return;

            find = treeView1.Nodes.Find(foNode.Id, true);

            node = find.Any() ? find.First() : nodes.Add(foNode.Id, foNode.Name, foNode.IdImage, foNode.IdImage);
            node.Tag = foNode;
        }

        private int GetImageId(FONode foNode)
        {
            if (foNode is FOSolution)
            {
                return 10;
            }
            if (foNode is FODataSourceDBProject)
            {
                return 8;
            }
            if (foNode is FODataSourceDBClass)
            {
                return 12;
            }
            if (foNode is FODataSourceDBProperty)
            {
                return 9;
            }
            if (foNode is FOBusinessProject)
            {
                return 8;
            }
            if (foNode is FOBusinessClass)
            {
                return 12;
            }
            if (foNode is FOBusinessProperty)
            {
                return 9;
            }
            if (foNode is FOPropertyValidationNode)
            {
                return 6;
            }
            return -1;
        }

        private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
        {
            var node = treeView1.SelectedNode;

            e.Cancel = node == null;

            if (node == null || e.Cancel || node.Tag == null) return;

            contextMenuStrip1.Items.Clear();

            if (node.Tag is FOSolution)
            {
                contextMenuStrip1.Items.AddRange(new ToolStripItem[]
                                                     {
                                                         addDatabaseMenuItem, toolStripSeparator3,
                                                         consolidateToolStripMenuItem, editToolStripMenuItem
                                                     });
            }
            if (node.Tag is FODataSourceDBProject)
            {
                contextMenuStrip1.Items.AddRange(new ToolStripItem[]
                                                     {
                                                         generateBusinessMenuItem, toolStripSeparator3,
                                                         consolidateToolStripMenuItem, editToolStripMenuItem,
                                                         toolStripSeparator1, removeToolStripMenuItem
                                                     });
            }
            if (node.Tag is FODataSourceDBClass)
            {
                contextMenuStrip1.Items.AddRange(new ToolStripItem[]
                                                     {
                                                         addFactoryToolStripMenuItem, toolStripSeparator3,
                                                         consolidateToolStripMenuItem, editToolStripMenuItem
                                                     });
            }
            if (node.Tag is FODataSourceDBProperty)
            {
                contextMenuStrip1.Items.AddRange(new ToolStripItem[]
                                                     {
                                                         addValidationToolStripMenuItem, toolStripSeparator3,
                                                         consolidateToolStripMenuItem, editToolStripMenuItem
                                                     });
            }
            if (node.Tag is FOBusinessProject)
            {
                contextMenuStrip1.Items.AddRange(new ToolStripItem[]
                                                     {
                                                         consolidateToolStripMenuItem, editToolStripMenuItem,
                                                         toolStripSeparator1, removeToolStripMenuItem
                                                     });
            }
            if (node.Tag is FOBusinessClass)
            {
                contextMenuStrip1.Items.AddRange(new ToolStripItem[]
                                                     {
                                                         addMethodToolStripMenuItem, toolStripSeparator3,
                                                         consolidateToolStripMenuItem, editToolStripMenuItem,
                                                         toolStripSeparator1, removeToolStripMenuItem
                                                     });
            }
            var foBusinessProperty = node.Tag as FOBusinessProperty;
            if (foBusinessProperty != null)
            {
                consolidateToolStripMenuItem.Visible = ((foBusinessProperty).IsDataBound);
                contextMenuStrip1.Items.AddRange(new ToolStripItem[]
                                                     {
                                                         addValidationToolStripMenuItem, toolStripSeparator3,
                                                         consolidateToolStripMenuItem, editToolStripMenuItem,
                                                         toolStripSeparator1, removeToolStripMenuItem
                                                     });
            }
            if (node.Tag is FOPropertyValidationNode)
            {
                contextMenuStrip1.Items.AddRange(new ToolStripItem[]
                                                     {
                                                         editToolStripMenuItem, toolStripSeparator1,
                                                         removeToolStripMenuItem
                                                     });
            }
        }

        private void addValidationToolStripMenuItem_Click(object sender, EventArgs e)
        {
        }

        private void addMethodToolStripMenuItem_Click(object sender, EventArgs e)
        {
        }

        private void addFactoryToolStripMenuItem_Click(object sender, EventArgs e)
        {
        }

        private void editToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (treeView1.SelectedNode == null || treeView1.SelectedNode.Tag == null) return;

            var form = FormFactory.GetForm(treeView1.SelectedNode.Tag as FONode, Connector);

            if (form != null)
            {
                form.ShowDialog();
            }
            else
            {
                MessageBox.Show(Resources.Manager_type_not_supported);
            }
        }

        private void consolidateToolStripMenuItem_Click(object sender, EventArgs e)
        {
        }

        private void removeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (treeView1.SelectedNode == null || treeView1.SelectedNode.Tag == null) return;

            var node = treeView1.SelectedNode;

            node.Remove();

            var foNode = node.Tag as FONode;
            Debug.Assert(foNode != null, "foNode != null");
            var parentFoNode = foNode.Parent;
            parentFoNode.RemoveNode(foNode);
        }

        private void addDatabaseMenuItem_Click(object sender, EventArgs e)
        {
            var form = new DatabaseProjectManager();
            form.DataBind(new DataBaseConnectionModel(), FOSolution.Instance.DataSourceDBProjects);
            form.ShowDialog(this);

            if (form.FoProject == null) return;

            var node = treeView1.Nodes.Find(form.FoProject.OUID, true).FirstOrDefault();
            if (node != null)
            {
                // Remove node and force readd?
                node.Remove();
                node = null;
            }


            CreateNode(ref node, form.FoProject);
        }

        private void generateBusinessMenuItem_Click(object sender, EventArgs e)
        {
            if (treeView1.SelectedNode == null || treeView1.SelectedNode.Tag == null ||
                !(treeView1.SelectedNode.Tag is FODataSourceDBProject)) return;

            var dbProj = treeView1.SelectedNode.Tag as FODataSourceDBProject;

            var name = dbProj.BaseNameSpace.Replace(".Dal", ".Business");

            var resultProject = FOSolution.Instance.BusinessProjects.Contains(name)
                                    ? FOSolution.Instance.BusinessProjects.Cast<FOBusinessProject>().First
                                          (item => item.Name == name)
                                    : new FOBusinessProject(FOSolution.Instance, name, name,
                                                            FOProjectType.Library);

            resultProject.MapDataSourceClasses(dbProj.DataSourceDBClasses);

            var nodes = treeView1.Nodes.Find(resultProject.Parent.Id, false);
            var node = nodes.Length > 0 ? nodes[0] : null;
            FillTree(node, resultProject);
        }

        private void GenerateUiMenuItemClick(object sender, EventArgs e)
        {
        }

        private void refreshToolStripButton_Click(object sender, EventArgs e)
        {
            DataBind(Connector, _typesToShow);
        }

        /// <summary>
        ///   Occurs when the treeview changed selection
        /// </summary>
        public event FoSolutionExplorerUserControlEventHandler SelectionChanged;

        private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (SelectionChanged != null)
                SelectionChanged(sender, new FoSolutionExplorerEventArgs(e.Node.Tag as FONode));
        }
    }

    /// <summary>
    /// </summary>
    public class FoSolutionExplorerEventArgs
    {
        /// <summary>
        /// </summary>
        /// <param name="currentNode"> </param>
        public FoSolutionExplorerEventArgs(FONode currentNode)
        {
            CurrentNode = currentNode;
        }

        /// <summary>
        /// </summary>
        public FoSolutionExplorerEventArgs()
        {
        }

        /// <summary>
        /// </summary>
        public FONode CurrentNode { get; set; }
    }
}